package com.xiaozhu.utils;

import com.xiaozhu.mapper.PermissionMapper; // 操作权限表的 Mapper，用于插入/查询权限
import com.xiaozhu.mapper.RolePermissionMapper; // 操作角色-权限表的 Mapper
import com.xiaozhu.pojo.Entity.Permission; // 权限实体类
import com.xiaozhu.pojo.constant.RoleConstant; // 系统常量类，包含管理员角色 ID
import lombok.extern.slf4j.Slf4j; // Lombok 注解，生成 log 日志对象
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.ApplicationArguments; // ApplicationRunner 回调参数
import org.springframework.boot.ApplicationRunner; // 应用启动完成后执行的接口
import org.springframework.stereotype.Component; // 将类注册到 Spring 容器
import org.springframework.web.bind.annotation.RequestMethod; // HTTP 方法枚举
import org.springframework.web.method.HandlerMethod; // 控制器方法封装对象
import org.springframework.web.servlet.mvc.method.RequestMappingInfo; // 请求映射信息
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping; // 获取所有控制器映射

import java.util.HashSet;
import java.util.Map;
import java.util.Set;

/**
 * PermissionScanner
 *
 * 功能：
 * 1. 应用启动时扫描系统中所有 Controller 的请求映射（URL + HTTP 方法）。
 * 2. 根据方法名和请求方式生成权限标识（如 GET:/user/list）。
 * 3. 如果权限表中不存在该权限，则插入 sys_permission 表。
 * 4. 同时更新角色-权限关联表，将权限分配给管理员角色。
 *
 * 注意：
 * - 每次应用启动都会执行一次。
 * - 使用 ApplicationRunner 保证在 Spring 容器完全启动后执行。
 * - 兼容 Spring Boot 2.x 和 3.x 的 URL 条件获取方式。
 */
@Component
@Slf4j
public class PermissionScanner implements ApplicationRunner {

    // 注入 Spring MVC 提供的 RequestMappingHandlerMapping，用于获取所有控制器映射
    @Autowired
    private RequestMappingHandlerMapping requestMappingHandlerMapping;

    // 注入权限表 Mapper
    @Autowired
    private PermissionMapper permissionMapper;

    // 注入角色-权限关联表 Mapper
    @Autowired
    private RolePermissionMapper rolePermissionMapper;

    /**
     * 应用启动后执行的方法
     *
     * @param args 应用启动参数
     */
    @Override
    public void run(ApplicationArguments args) throws Exception {

        // 获取系统中所有请求映射：RequestMappingInfo -> HandlerMethod
        // 例如 GET /user/list -> UserController.list()
        Map<RequestMappingInfo, HandlerMethod> handlerMethods =
                requestMappingHandlerMapping.getHandlerMethods();

        // 遍历每一条映射
        for (Map.Entry<RequestMappingInfo, HandlerMethod> entry : handlerMethods.entrySet()) {
            RequestMappingInfo requestMappingInfo = entry.getKey(); // 请求映射信息（包含 URL、HTTP 方法等）
            HandlerMethod handlerMethod = entry.getValue(); // 对应的控制器方法对象

            // ------------------ 输出调试信息 ------------------
            log.info("requestMappingInfo:{}", requestMappingInfo); // 例如 {GET [/user/info]}
            log.info("handlerMethod:{}", handlerMethod); // 例如 com.xiaozhu.controller.UserController#info()
            log.info("patternValues:{}", requestMappingInfo.getPathPatternsCondition().getPatternValues()); // URL 模式集合

            // ------------------ 获取 URL ------------------
            Set<String> patterns = new HashSet<>();
            // Spring Boot 3.x 获取方式
            if (requestMappingInfo.getPathPatternsCondition() != null) {
                patterns.addAll(requestMappingInfo.getPathPatternsCondition().getPatternValues());
            }
            // Spring Boot 2.x 获取方式
            else if (requestMappingInfo.getPatternsCondition() != null) {
                patterns.addAll(requestMappingInfo.getPatternsCondition().getPatterns());
            }
            log.info("patterns:{}", patterns); // 输出 URL 列表

            // ------------------ 获取 HTTP 方法 ------------------
            Set<RequestMethod> methods = requestMappingInfo.getMethodsCondition().getMethods();
            log.info("methods:{}", methods); // 输出 HTTP 方法，如 [GET]

            // ------------------ 插入权限表逻辑 ------------------
            // 一个映射可能有多个 URL，一个 URL 可能支持多个 HTTP 方法  GET:/user/info 可能 POST:/user/info PUT:/user/info
            for (String url : patterns) {
                for (RequestMethod method : methods) {

                    // 拼接唯一权限码，例如 GET:/user/list
                    String permissionCode = method + ":" + url;
                    log.info("初始化权限表：{}", permissionCode);

                    // 获取方法名，例如 addAdmin、deleteUser
                    String permissionName = handlerMethod.getMethod().getName();

                    // 查询当前权限是否已存在
                    Permission permission = permissionMapper.selectList(permissionName);
                    log.info("permission: {}", permission); // null 表示权限不存在

                    if (permission == null) {
                        try {
                            // 插入权限表
                            permissionMapper.insert(permissionCode, permissionName);
                            log.info("执行完毕 {}", permissionCode);

                            // 同步角色-权限关系表，将权限赋给管理员角色
                            rolePermissionMapper.insert(permission.getId(), RoleConstant.ADMIN_ID);

                        } catch (Exception e) {
                            // 插入失败日志
                            log.error("写入权限表失败: {} - {}", permissionCode, permissionName, e);
                        }
                    }
                }
            }
        }
    }
}
